<?php
/**
 * @Description procJSON的php实现
 * @Sonkwl Xiong
 * @Date 2021/12/29 09:26:03
 */
//@Sonkwl Xiong 2022/02/22 08:57:37
//@Desc 新增开放模型(无需jwt验证)

namespace procjson;

class app{
    static public $json=array();//post
    static public $PDO="mysql:host=10.202.8.204;dbname=xczx";
	static public $user="test";
	static public $pwd="test";
    static public $db_tables=array();//db映射
    static public $model_open=array();//开放模型
    static public $model_fixed=array();//强制模型

    static public $appid=array();//app编号
    static public $auth_table=array("table"=>"","id"=>"","appid"=>"");//用戶權限驗證
    static public $session_no='@ALL';
    static public $keystr='WHSS';
    static public $keyint=7;
    static public $jwt="";//jwt版本
    static public $exp="";
    static public $filepath="";//文件保存路径

    //@Desc PDO初始化
    static public function GetPDO(){
        try{
			$db=new \PDO(self::$PDO,self::$user,self::$pwd);
			return $db;
		}catch(PDOException $e){
            \procjson\http::Response(array("res"=>"NG","message"=>$e->getMessage()));
		}
    }

    //@Desc JWT
    static public function JWT($db,$step,$json){
        if($json["command"]!="jwt"){
            return;
        }
        self::$session_no=\procjson\http::DecodeToken($json["token"]);
    }

    //@Desc login操作
    static public function Login($db,$step,$json){
        if($json["command"]!="login"){
            return;
        }

        $table_name=self::HandlerTable($json["table"]);
        $where=self::HandlerWhere($json["clause"],1);//强制=
        $table_clause=$where["where"];
        $table_value=$where["params"];

        $sql="select count(*) from ".$table_name.$table_clause;
        $dbh=$db->prepare($sql);
        $dbh->execute($table_value);
        $rs=$dbh->fetchAll();
        
        if($rs[0][0]==0){
            \procjson\http::Response(array("res"=>"NG","message"=>"登录失败"));
        }
        self::$json[$step]["token"]=\procjson\jwt::SetJWT($json["clause"][$json["id"]]);
        if(self::$jwt=="V1"){
            self::$json[$step]["token"]=\procjson\jwt::SetJWTV1($json["clause"][$json["id"]]);
        }
    }
    
    //@Desc 单笔查询
    static public function Query($db,$step,$json){
        if($json["command"]!="query"){
            return;
        }

        $table_name=self::HandlerTable($json["table"]);
        $where=self::HandlerWhere($json["clause"],0);
        $table_clause=$where["where"];
        $table_value=$where["params"];
        $table_column=isset($json["column"])?$json["column"]:"*";

        $sql="select ".(isset($json["column"])?$json["column"]:"*")." from ".$table_name.$table_clause;
     
        $dbh=$db->prepare($sql);
        $dbh->execute($table_value);
        $rs=$dbh->fetchAll(\PDO::FETCH_ASSOC);
        //echo $sql; exit;
        if(count($rs)==0){
            //@Sonkwl Xiong 2022/01/06 08:02:42
            //@Desc 验证数据不存在
            if(!isset($json["exists"]) || $json["exists"]!="NONE"){
                \procjson\http::Response(array("res"=>"NG","message"=>"数据不存在"));
            }
        }else{
            if(isset($json["exists"]) && $json["exists"]=="NONE"){
                \procjson\http::Response(array("res"=>"NG","message"=>"数据存在"));
            }
            self::$json[$step]["clause"]=$rs[0];
        }
    }

    //@Desc 多笔查询
    static public function Select($db,$step,$json){
        if($json["command"]!="select"){
            return;
        }
        $table_name=self::HandlerTable($json["table"]);
        $where=self::HandlerWhere($json["clause"],0);
        $table_clause=$where["where"];
        $table_value=$where["params"];
        
        $page=isset($json["page"])?$json["page"]:1;
        $slice=isset($json["slice"])?$json["slice"]:10;
        $table_order=isset($json["order"])?' order by '.$json["order"]:"";
        $table_limit=" limit ".($page*$slice-$slice).",".$slice;
        if($slice==0){
            //全表查询
            $table_limit="";
        }
        $sql="select ".(isset($json["column"])?$json["column"]:"*")." from ".$table_name.$table_clause.$table_order.$table_limit;
        // if($step=="step3"){
        //     echo $sql;
        //     print_r($table_value);
        // }

        
        $sql_count="select count(*) from ".$table_name.$table_clause;
        $rows=0;
        $pages=0;

        $dbh=$db->prepare($sql);
        $dbh->execute($table_value);
        $list=$dbh->fetchAll(\PDO::FETCH_ASSOC);

        if($slice!=0){
            $dbh=$db->prepare($sql_count);
            $dbh->execute($table_value);
            $rs=$dbh->fetchAll();
            $rows=$rs[0][0];
            $pages=(int)($rows/$slice)+($rows%$slice?1:0);
        }
        
        self::$json[$step]["list"]=$list;
        self::$json[$step]["rows"]=$rows;
        self::$json[$step]["pages"]=$pages;
        self::$json[$step]["page"]=$page;
    }

    //@Desc 新增操作
    static public function Insert($db,$step,$json){
        if($json["command"]!="insert"){
            return;
        }
        $table_name=self::HandlerTable($json["table"]);
        $pre=array();
        $val=array();
        foreach ($json["clause"] as $key => $value) {
            array_push($pre,"?");
            array_push($val, self::HandlerValue($value));
        }
        $sql="insert into ".$table_name."(".implode(",",array_keys($json["clause"])).") values(". implode(",",$pre).");";
        $dbh=$db->prepare($sql);
        $dbh->execute($val);
    }

    //@Desc 新增但不存在
    static public function InsertNoExists($db,$step,$json){
        if($json["command"]!="insertNoExists"){
            return;
        }
        $table_name=self::HandlerTable($json["table"]);
        //比对是否存在
        $where=self::HandlerWhere($json["noexists"],1);
        $table_clause=$where["where"];
        $table_value=$where["params"];
        $sql="select * from ".$table_name.$table_clause;
        $dbh=$db->prepare($sql);
        $dbh->execute($table_value);
        $rs=$dbh->fetchAll();
        if(count($rs)>0){
            return;
        }

        $pre=array();
        $val=array();
        foreach ($json["clause"] as $key => $value) {
            array_push($pre,"?");
            array_push($val, self::HandlerValue($value));
        }
        $sql="insert into ".$table_name."(".implode(",",array_keys($json["clause"])).") values(". implode(",",$pre).");";
        $dbh=$db->prepare($sql);
        $dbh->execute($val);
    }
    //@Desc 先删除再新增
    static public function InsertAfterDelete($db,$step,$json){
        if($json["command"]!="insertAfterDelete"){
            return;
        }
        $table_name=self::HandlerTable($json["table"]);
        //先删除
        $where=self::HandlerWhere($json["delete"],1);
        $table_clause=$where["where"];
        $table_value=$where["params"];
        $sql="delete from ".$table_name.$table_clause;
        $dbh=$db->prepare($sql);
        $dbh->execute($table_value);

        $pre=array();
        $val=array();
        foreach ($json["clause"] as $key => $value) {
            array_push($pre,"?");
            array_push($val, self::HandlerValue($value));
        }
        $sql="insert into ".$table_name."(".implode(",",array_keys($json["clause"])).") values(". implode(",",$pre).");";
        $dbh=$db->prepare($sql);
        $dbh->execute($val);
    }
    

    //@Desc 更新操作
    static public function Update($db,$step,$json){
        if($json["command"]!="update"){
            return;
        }
        $table_name=self::HandlerTable($json["table"]);
        $where=self::HandlerWhere($json["clause"],1);
        $table_clause=$where["where"];
        $table_value=$where["params"];
  
        $table_update=' set ';
        $val=array();
        foreach ($json["update"] as $column => $value) {
            $table_update.= $column."=?,";//强制=
            array_push($val,self::HandlerValue($value));
        }
        $table_update=trim($table_update,",");
        if($table_clause==""){
            \procjson\http::Response(array("res"=>"NG","message"=>"更新操作，clause必须有数据"));
        }

        foreach ($table_value as $key => $value) {
            array_push($val,$value);
        }
        //print_r($val); exit;
        $sql="update ".$table_name.$table_update.$table_clause;
        $dbh=$db->prepare($sql);
        $dbh->execute($val);
    }

    //@Desc 删除操作
    static public function Delete($db,$step,$json){
        if($json["command"]!="delete"){
            return;
        }
        $table_name=self::HandlerTable($json["table"]);
        $where=self::HandlerWhere($json["clause"],1);
        $table_clause=$where["where"];
        $table_value=$where["params"];

        if($table_clause==""){
            \procjson\http::Response(array("res"=>"NG","message"=>"刪除操作，clause必须有数据"));
        }

        $sql="delete from ".$table_name.$table_clause;
        $dbh=$db->prepare($sql);
        $dbh->execute($table_value);
    }

    //@Desc 特殊值
    static public function HandlerValue($value){
        $value=$value==="@token"?self::$session_no:$value;
        $value=$value==="@time"?date("Y-m-d H:i:s"):$value;
        $value=$value==="@date"?date("Y-m-d"):$value;
        $value=$value==="@NULL"?"":$value;//值为空
        //图片
        if(strstr($value,"data:image")){
            $value=\procjson\upfile::Img($value);
        }
        //pdf
        if(strstr($value,"data:application/pdf")){
            $value=\procjson\upfile::Pdf($value);
        }
        return htmlspecialchars($value,ENT_NOQUOTES);
    }

    //@desc 验证db_table
    static public function HandlerTable($tbl){
        if(!isset(self::$db_tables[$tbl])){
            \procjson\http::Response(array("res"=>"NG","message"=>"[".$tbl."]的对应表不存在"));
        }
        return self::$db_tables[$tbl];
    }

    //$Desc 验证栏位必须符合要求no,s_no,s_group_name
    static public function CheckInput($val){
        $regex="/^\w+(_|\w+)$/";
        if(!preg_match($regex,$val)){
            \procjson\http::Response(array("res"=>"NG","message"=>$val."不符合规则"));
        }
        return $val;
    }

    //@Desc 获得DML where部分
    static public function HandlerWhere($clause,$mod){
        $table_where='';
        $params=array();
        foreach($clause as $key=>$value){
            $key=self::CheckInput($key);//验证栏位
            if($value==""){
                continue;
            }
            if(is_array($value)){
                if(count($value)==0){
                    continue;
                }
                //between
                if(count($value)==3 && $value[0]=="between"){
                    $table_where.=($table_where==""?" where ":" and ").$key." between ? and ?";
                    array_push($params,self::HandlerValue($value[1]));
                    array_push($params,self::HandlerValue($value[2]));
                    continue;
                }
                //in
                $val=array();
                for($i=0;$i<count($value);$i++){
                    array_push($val,"?");
                    array_push($params,self::HandlerValue($value[$i]));
                }
                $table_where.=($table_where==""?" where ":" and ").$key." in(".implode(",",$val).")";
                continue;
            }
            //拼接处理
            if(strstr($value,"@STEP")){
                $str_sub=explode(":",trim($value,"@"));
                if(count($str_sub)!=3){
                    \procjson\http::Response(array("res"=>"NG","message"=>"@STEP格式无效"));
                }
                if(!isset(self::$json["step".$str_sub[1]]["list"])){
                    \procjson\http::Response(array("res"=>"NG","message"=>"STEP".$str_sub[1]."不是select操作"));
                }
                $val=array();
                $temp_list=self::$json["step".$str_sub[1]]["list"];
                if(count($temp_list)==0){
                    $table_where.=($table_where==""?" where 0=1 ":" and 0=1 ");
                    continue;
                }
                for($i=0;$i<count($temp_list);$i++){
                    array_push($val,"?");
                    array_push($params,$temp_list[$i][$str_sub[2]]);
                }
                $table_where.=($table_where==""?" where ":" and ").$key." in(".implode(",",$val).")";
                continue;
            }
            if($mod==1){
                //强制等于,不存在like
                $table_where.=($table_where==""?" where ":" and ").$key."= ?";
                array_push($params,self::HandlerValue($value));
                continue;
            }
            //非强制模块，允许like查询
            $table_where.=($table_where==""?" where ":" and ").$key.(strstr($value,"%")?" like ":"=")."?";
            array_push($params,self::HandlerValue($value));
        }
        return array(
            "where"=>$table_where,
            "params"=>$params
        );
    }

    //@Desc 运行框架
    static public function Run(){
        //打開數據鏈接
        $db=self::GetPDO();
        //設置開放模型
        \procjson\model::$model_open=self::$model_open;
        //设置强制模型
        \procjson\model::$model_fixed=self::$model_fixed;
        //設置jwt
        \procjson\jwt::$keystr=self::$keystr;
        \procjson\jwt::$keyint=self::$keyint;
        \procjson\jwt::$jwt=self::$jwt;
        \procjson\jwt::$exp=self::$exp;
        //设置验证模块
        \procjson\auth::$appid=self::$appid;
        \procjson\auth::$auth_table=self::$auth_table;
        //文件存储处理
        \procjson\upfile::$filepath=self::$filepath;
        //獲得請求數據
        self::$json=\procjson\http::Request();
        //事件執行
        try{
            $db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
            $db->beginTransaction();
            foreach(self::$json as $step=>$json){
                if($step=="res" || $step=="message"){
                    // 跳过返回值
                    continue;
                }
                //验证请求模型
                \procjson\model::CheckCommand($json);
                //验证开放模型
                \procjson\model::CheckOpen($json,self::$session_no);
                //验证强制模型
                \procjson\model::CheckFixed($json,self::$session_no);
                //验证auth
                \procjson\auth::Handler($db,self::$session_no);

                self::Login($db,$step,$json);
                self::JWT($db,$step,$json);
                self::Query($db,$step,$json);
                self::Select($db,$step,$json);
                self::Insert($db,$step,$json);
                self::InsertAfterDelete($db,$step,$json);
                self::InsertNoExists($db,$step,$json);
                self::Update($db,$step,$json);
                self::Delete($db,$step,$json);
            }
            $db->commit();
            self::$json["res"]="OK";
            self::$json["message"]="操作成功";
            \procjson\http::Response(self::$json);
        }catch(\Exception $e){
            $db->rollBack();
            \procjson\http::Response(array("res"=>"NG","message"=>$e->getMessage()));
        }
    }
}
?>